package com.zc.app.shiro.session.scheduler;

import com.zc.app.shiro.utils.JdbcTemplateUtils;
import com.zc.app.shiro.utils.SerializableUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * Created by zc on 2016/7/19.
 */
public class MySessionValidationScheduler implements SessionValidationScheduler, Runnable {

    private static final Logger log = LogManager.getLogger(MySessionValidationScheduler.class);

    private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();

    private ValidatingSessionManager sessionManager;

    private ScheduledExecutorService scheduledExecutorService;

    private long interval = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL;

    private boolean enabled = false;

    public MySessionValidationScheduler() {
    }

    @Override
    public void run() {
        log.info("Executing session validation...");
        long startTime = System.currentTimeMillis();

        String sql = "SELECT SESSION FROM SESSIONS LIMIT ? OFFSET ? ";
        int start = 0;
        int size = 20;
//        List<String> sessionList = jdbcTemplate.queryForList(sql, String.class, size, start);
//        while(sessionList.size() > 0) {
//            for (String sessionStr : sessionList){
//                try {
//                    Session session = SerializableUtils.deserialize(sessionStr);
//                    Method validatedMethod = ReflectionUtils.findMethod(AbstractValidatingSessionManager.class,
//                            "validate",
//                            Session.class,
//                            SessionKey.class);
//                    validatedMethod.setAccessible(true);
//                    ReflectionUtils.invokeMethod(validatedMethod,
//                            sessionManager,
//                            session,
//                            new DefaultSessionKey(session.getId()));
//                } catch (Exception ex){
//                    log.error(ex.getMessage(),ex);
//                }
//            }
//
//            start += size;
//            sessionList = jdbcTemplate.queryForList(sql, String.class, size, start);
//        }

        long stopTime = System.currentTimeMillis();

//        String messageStr = "Session validation completed successfully in %d milliseconds";
//        log.info(String.format(messageStr,(stopTime - startTime)));

    }

    @Override
    public boolean isEnabled() {
        return this.enabled;
    }

    @Override
    public void enableSessionValidation() {
        if(this.interval > 0l){
            this.scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setDaemon(true);
                    return thread;
                }
            });
            this.scheduledExecutorService.scheduleAtFixedRate(this, interval, interval, TimeUnit.MILLISECONDS);
            this.enabled = true;
        }
    }

    @Override
    public void disableSessionValidation() {
        this.scheduledExecutorService.shutdown();
        this.enabled = false;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public ValidatingSessionManager getSessionManager() {
        return sessionManager;
    }

    public void setSessionManager(ValidatingSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    public ScheduledExecutorService getScheduledExecutorService() {
        return scheduledExecutorService;
    }

    public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) {
        this.scheduledExecutorService = scheduledExecutorService;
    }

    public long getInterval() {
        return interval;
    }

    public void setInterval(long interval) {
        this.interval = interval;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}
